package com.yugao.fintech.draper.gateway.dynamic.route;

import com.yugao.fintech.draper.core.constant.CacheConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class CustomRouteDefinitionRepository implements RouteDefinitionRepository, ApplicationEventPublisherAware {

    private final RedisTemplate redisTemplate;

    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * 加载路由信息
     */
    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<CustomRouteDefinition> values = redisTemplate.opsForHash().values(CacheConstants.ROUTE_KEY);
        if (log.isDebugEnabled()) {
            log.debug("加载redis缓存中路由: {} 条， {}", values.size(), values);
        }
        return Flux.fromIterable(values);
    }

    /**
     * 保存路由信息
     */
    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        route.subscribe(this::saveRoute);
        return Mono.empty();
    }

    /**
     * 删除路由信息
     */
    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        routeId.subscribe(this::deleteByRouteId);
        return Mono.empty();
    }

    /**
     * 保存路由信息到redis
     */
    private void saveRoute(RouteDefinition routeDefinition) {
        CustomRouteDefinition customRouteDefinition = new CustomRouteDefinition();
        BeanUtils.copyProperties(routeDefinition, customRouteDefinition);
        redisTemplate.opsForHash().put(CacheConstants.ROUTE_KEY, customRouteDefinition.getId(), customRouteDefinition);
    }

    /**
     * 删除redis中的路由信息
     */
    private void deleteByRouteId(String id) {
        redisTemplate.opsForHash().delete(CacheConstants.ROUTE_KEY, id);
    }

    /**
     * 通知网关重新加载路由
     */
    public void publishEvent() {
        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
